
#ifndef __LIBERTY_LIBRARY_TASKSCHEDULER_H__
#define __LIBERTY_LIBRARY_TASKSCHEDULER_H__

#include <Liberty3D/Liberty3D.h>
#include <Liberty3D/Library/Task.h>
#include <Liberty3D/Engine/IObjectMethod.h>
#include <list>
#include <exception>
#include <boost/thread/mutex.hpp>

namespace Liberty { namespace Library {
    class TaskScheduler {
        friend class Task;

    protected:
        static boost::mutex                     _mutex;
        static std::list<std::shared_ptr<Task>> _tasks;
        static std::list<std::shared_ptr<Task>> _runningTasks;
        static volatile bool                    _running;

        static void reorder();

    protected:
        static void init();

    public:
        static void consoleInit();
        static bool consoleLoop(bool autoStopWhenDone = true);
        static void consoleStop();

    public:
        static bool isMainThread();

        static unsigned int numProcessors();

    public:
        static void schedule(const std::shared_ptr<Task>& task);
        static void cancel  (const std::shared_ptr<Task>& task);
        static void finished(const std::shared_ptr<Task>& task);

        static bool pooling();

    protected:
        static void scheduleImpl  (const std::shared_ptr<Task>& task);
        static void scheduleLocked(const std::shared_ptr<Task>& task);
        static void cancelImpl    (const std::shared_ptr<Task>& task);

        static void triggerTaskEvent();
        static void waitForTaskEvent(boost::mutex::scoped_lock&);

        static std::shared_ptr<Task> dequeue(bool mainThread);

        static bool hasPendingTasks();
        static bool waitForPendingTasks();

    public:
        template <typename RT, typename T>
        static std::shared_ptr<Task> scheduleMethod(const std::shared_ptr<T>& o, typename Liberty::Engine::ObjectMethod<RT, T>::member_type fn) {
            std::shared_ptr<Task> task(new Task());

            task->setMethod(std::shared_ptr<Liberty::Engine::IObjectMethod>(new Liberty::Engine::ObjectMethod<RT, T>(o, fn)));
            schedule(task);
            return task;
        }

        template <typename RT, typename T, typename A1, typename A1D>
        static std::shared_ptr<Task> scheduleMethod1(const std::shared_ptr<T>& o, typename Liberty::Engine::ObjectMethod1<RT, T, A1, A1D>::member_type fn, A1D a1) {
            std::shared_ptr<Task> task(new Task());

            task->addParameter(boost::any(a1));
            task->setMethod(std::shared_ptr<Liberty::Engine::IObjectMethod>(new Liberty::Engine::ObjectMethod1<RT, T, A1, A1D>(o, fn)));
            schedule(task);
            return task;
        }
    };
}}

#endif
